/*
    Project: OCMF (Operant Chamber Management Framework)
    Version: 1.0
    Author: Copyright (C) 2010, Samuel Delaney & Andrew Harvey
    Licence:
        This file is part of OCMF.

            OCMF is free software: you can redistribute it and/or modify
            it under the terms of the GNU General Public License as published by
            the Free Software Foundation, either version 3 of the License, or
            (at your option) any later version.

            OCMF is distributed in the hope that it will be useful,
            but WITHOUT ANY WARRANTY; without even the implied warranty of
            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
            GNU General Public License for more details.

            You should have received a copy of the GNU General Public License
            along with OCMF.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "DbClient.h"
#include "OcmfServer.h"

DbClient::DbClient(OcmfServer * ocmfServer)
{
    ownerOcmfServer = ocmfServer;

    //create the database object - this must be hardcoded since it links relevant drivers upon compilation
    QSqlDatabase mySqlDatabase = QSqlDatabase::addDatabase("QMYSQL","ocmf");

    //set database credentials
    mySqlDatabase.setHostName(ServerConfig::GetConfigVariable("DbHostname"));
    mySqlDatabase.setDatabaseName(ServerConfig::GetConfigVariable("DbInstance"));
    mySqlDatabase.setUserName(ServerConfig::GetConfigVariable("DbUsername"));
    mySqlDatabase.setPassword(ServerConfig::GetConfigVariable("DbPassword"));

    CleanDatabase();

    //update server status in database - set to idle
    SetServerStatus(OcmfServerStatus::Idle, NULL);
}

DbClient::~DbClient()
{
    CleanDatabase();
}

OcmfServer * DbClient::OwnerOcmfServer()
{
    return ownerOcmfServer;
}

void DbClient::CleanDatabase()
{
    QSqlDatabase mySqlDatabase;

    //get the database from the static class
    if(QSqlDatabase::database("ocmf",false).isValid())
        mySqlDatabase = QSqlDatabase::database("ocmf",false);
    else
    {
        Logger::AddEntry("Could not retrieve database connection");
        exit(EXIT_FAILURE);
    }

    //try to open a connection to the database
    if(!mySqlDatabase.open())
    {
        Logger::AddEntry("Could not open connection to database");
        exit(EXIT_FAILURE);
    }

    //create insert query bound to the current database
    QSqlQuery insertQuery(mySqlDatabase);

    //insert the SQL statement into the query
    insertQuery.prepare("DELETE FROM chambers WHERE chambers.hostName = :hostname");

    //bind the parameters to the query
    insertQuery.bindValue(":hostName", QHostInfo::localHostName());

    //execute sql query
    insertQuery.exec();
}

Experiment * DbClient::GetNextExperiment()
{
    QSqlDatabase mySqlDatabase;

    //get the database from the static class
    if(QSqlDatabase::database("ocmf",false).isValid())
        mySqlDatabase = QSqlDatabase::database("ocmf",false);
    else
    {
        Logger::AddEntry("Could not retrieve database connection");
        exit(EXIT_FAILURE);
    }

    //try to open a connection to the database
    if(!mySqlDatabase.open())
    {
        Logger::AddEntry("Could not open connection to database");
        exit(EXIT_FAILURE);
    }

    //create select query bound to the current database
    QSqlQuery selectQuery(mySqlDatabase);

    //insert the SQL statement into the query
    selectQuery.prepare("SELECT chambers.experimentName, chambers.experiment FROM chambers WHERE chambers.hostName = :hostName AND chambers.experimentName IS NOT NULL");

    //bind the serverId to the query
    selectQuery.bindValue(":hostName", QHostInfo::localHostName());

    //execute sql query
    if(!selectQuery.exec())
        Logger::AddEntry(selectQuery.lastError().text());

    //make sure rows have been returned
    if(selectQuery.size() > 0){
        //iterate to the first returned row
        selectQuery.next();

        //get the file returned from the query
        Experiment * experiment = new Experiment(selectQuery.value(0).toString(), selectQuery.value(1).toByteArray(), OwnerOcmfServer());

        //close the database connection
        mySqlDatabase.close();

        //return the experiment
        return experiment;
    }

    //close the database connection
    mySqlDatabase.close();

    //if the query has failed of there is no experiments scheduled for this server, return null pointer
    return NULL;
}

void DbClient::SetServerStatus(OcmfServerStatus::Status ocmfServerStatus, Experiment * experiment)
{
    QSqlDatabase mySqlDatabase;

    //get the database from the static class
    if(QSqlDatabase::database("ocmf",false).isValid())
        mySqlDatabase = QSqlDatabase::database("ocmf",false);
    else
    {
        Logger::AddEntry("Could not retrieve database connection");
        exit(EXIT_FAILURE);
    }

    //try to open a connection to the database
    if(!mySqlDatabase.open())
    {
        Logger::AddEntry("Could not open connection to database");
        exit(EXIT_FAILURE);
    }

    //create insert query bound to the current database
    QSqlQuery insertQuery(mySqlDatabase);

    //insert the SQL statement into the query
    insertQuery.prepare("INSERT INTO chambers VALUES (NULL, :hostName, :status, :ipAddress, NULL, NULL, NULL)");

    //bind the parameters to the query
    insertQuery.bindValue(":hostName", QHostInfo::localHostName());
    insertQuery.bindValue(":status", OcmfServerStatus::Parse(ocmfServerStatus));

    //try and get the ip address
    if(QNetworkInterface::interfaceFromName("eth0").isValid())
        insertQuery.bindValue(":ipAddress", QNetworkInterface::interfaceFromName("eth0").addressEntries()[0].ip().toString());
    else
    {
        Logger::AddEntry("Could not find eth0 network interface");
        exit(EXIT_FAILURE);
    }

    //execute sql query
    if(!insertQuery.exec())
        Logger::AddEntry(insertQuery.lastError().text());
}

void DbClient::AddExperimentResult(QByteArray  * experimentResultBytes)
{
    QSqlDatabase mySqlDatabase;

    //get the database from the static class
    if(QSqlDatabase::database("ocmf",false).isValid())
        mySqlDatabase = QSqlDatabase::database("ocmf",false);
    else
    {
        Logger::AddEntry("Could not retrieve database connection");
        exit(EXIT_FAILURE);
    }

    //try to open a connection to the database
    if(!mySqlDatabase.open())
    {
        Logger::AddEntry("Could not open connection to database");
        exit(EXIT_FAILURE);
    }

    //create select query bound to the current database
    QSqlQuery insertQuery(mySqlDatabase);

    //insert the SQL statement into the query
    insertQuery.prepare("INSERT INTO results VALUES (NULL, :file, :serverId: , NOW())");

    //bind the parameters to the query
    insertQuery.bindValue(":file", *experimentResultBytes);
    insertQuery.bindValue(":serverId", OwnerOcmfServer()->serverId);

    //execute sql query
    if(!insertQuery.exec())
    {
        Logger::AddEntry(insertQuery.lastError().text());
        exit(EXIT_FAILURE);
    }

    //close the database connection
    mySqlDatabase.close();
}
